using CommandLine;
using JamesFan.FetchAreaCodes.Consumer;
using JamesFan.FetchAreaCodes.Repository.MySql;
using JamesFan.FetchAreaCodes.Repository.Sqlite;
using Viyi.Strings.Extensions;
using Viyi.Util.Extensions;

namespace JamesFan.FetchAreaCodes.Cli;

internal sealed class OptionsManager {
    public static OptionsManager Parse(string[] args) {
        return new OptionsManager(args);
    }

    OptionsManager(string[] args) {
        var optionTypes = new[] {
            typeof(CliOptions),
            typeof(SqliteOptions),
            typeof(MysqlOptions)
        };

        CommandLine.Parser.Default.ParseArguments(args, optionTypes)
            .WithParsed<SqliteOptions>(options => Cli = Sqlite = options)
            .WithParsed<MysqlOptions>(options => Cli = Mysql = options)
            .WithNotParsed(errors => {
                if (errors.Any(err => err is HelpVerbRequestedError)) {
                    Environment.Exit(0);
                }
                else {
                    Environment.Exit(1);
                }
            });

        Cli?.Also(options => {
            if (options.ShowVersion) {
                WriteLine($"FetchAreaCodes verion {CliVersion.GetVersion()}");
                Environment.Exit(0);
            }

            try {
                Cli?.Validate();
            }
            catch (Exception ex) {
                WriteLine(ex.Message);
                Environment.Exit(2);
            }
        });
    }

    public CliOptions? Cli { get; private set; }
    public SqliteOptions? Sqlite { get; private set; }
    public MysqlOptions? Mysql { get; private set; }

    public void ConfigureWalker(DataWalker walker) {
        Cli?.Also(options => {
            walker.MaxLevel = options.MaxLevel;
            if (options.Console) {
                walker.AddConsumer(new ConsoleConsumer());
            }
        });

        Sqlite?.Also(options => {
            if (!options.FilePath.IsEmpty()) {
                walker.AddConsumer(new RepositoryConsumer(
                    new SqliteRepository(options.FilePath).Initialize()
                ));
            }
        });

        Mysql?.Also(options => {
            var connString = options.ConnectionString
                ?? MySqlRepository.BuildConnectionString(DbConfiguration.Load(options.ConfigFile!));
            walker.AddConsumer(new RepositoryConsumer(
                new MySqlRepository(connString).Initialize()
            ));
        });
    }
}
